# -*- coding: UTF-8 -*-
from io import BytesIO
import ssl,sys,os,_thread,json,re,posixpath

ROOT=os.path.abspath(os.path.dirname(os.path.abspath(__file__))+"/../")
sys.path.append(os.path.abspath(ROOT+"/libs"))
isPy3=(sys.version[0]=="3")
isPy2=(sys.version[0]=="2")
if isPy2:
    import BaseHTTPServer,SimpleHTTPServer


import argparse
import sys

def parseUrl(url):
    if isPy2:
        import urlparse
        return dict([(k, v[0]) for k, v in urlparse.parse_qs(url).items()])
    elif isPy3:
        from urllib.parse import parse_qs
        return dict([(k, v[0]) for k, v in parse_qs(url).items()])

def urldecode(arg):
    if isPy3:
        import urllib.parse
        return urllib.parse.unquote(arg)
    elif isPy2:
        import urllib
        return urllib.unquote(arg)



def _warn(args):
    print("\033[1;31;40m"+args+"\033[0m") 
def _info(args):
    print("\033[1;32;40m"+args+"\033[0m") 
def main():
    print(sys.argv)



config={}
confPath=ROOT+"/conf/conf.json"
with open(confPath,"r") as f:
    config=json.load(f)
ztoken=config["ztk"]
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-ht')
    #, action='store_true' 转为True/False
    parser.add_argument('-hs')
    args, left = parser.parse_known_args()
    if hasattr(args,'ht') and args.ht!=None and args.ht.isdigit():
        args.ht=(int)(args.ht)
        if args.ht>0 and args.ht<65535:
            config['httpPort']=args.ht
    if hasattr(args,'hs') and args.hs!=None and  args.hs.isdigit():
        args.hs=(int)(args.hs)
        if args.hs>0 and args.hs<65535:
            config['httpsPort']=args.hs           

_info("Listen on:")
del(config["ztk"])
print(config)
from http.server import HTTPServer, BaseHTTPRequestHandler

keyDir="keys/"
keyFile=keyDir+"key.pem"
certFile=keyDir+"cert.pem"


class pyhttp(BaseHTTPRequestHandler):
    def translate_path(self, path):
        """Translate a /-separated PATH to the local filename syntax.
        """
        # abandon query parameters
        path = path.split('?',1)[0]
        path = path.split('#',1)[0]
        path = posixpath.normpath(urldecode(path))
        words = path.split('/')
        words = [_f for _f in words if _f]
        path = os.getcwd()
        for word in words:
            drive, word = os.path.splitdrive(word)
            head, word = os.path.split(word)
            if word in (os.curdir, os.pardir): continue
            path = os.path.join(path, word)
        return path
    def deal_post_data(self):
        content_type = self.headers['content-type']
        if not content_type:
            return (False, "Content-Type header doesn't contain boundary")
        boundary = content_type.split("=")[1].encode()
        remainbytes = int(self.headers['content-length'])
        line = self.rfile.readline()
        remainbytes -= len(line)
        if not boundary in line:
            return (False, "Content NOT begin with boundary")
        line = self.rfile.readline()
        remainbytes -= len(line)
        fn = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"', line.decode())
        if not fn:
            return (False, "Can't find out file name...")
        path = self.translate_path(self.path)
        fn = os.path.join(path, config["upload_path"]+"/"+fn[0])
        line = self.rfile.readline()
        remainbytes -= len(line)
        line = self.rfile.readline()
        remainbytes -= len(line)
        try:
            out = open(fn, 'wb')
        except IOError:
            return (False, "Can't create file to write, do you have permission to write?")
                
        preline = self.rfile.readline()
        remainbytes -= len(preline)
        while remainbytes > 0:
            line = self.rfile.readline()
            remainbytes -= len(line)
            if boundary in line:
                preline = preline[0:-1]
                if preline.endswith(b'\r'):
                    preline = preline[0:-1]
                out.write(preline)
                out.close()
                return (True, "File '%s' upload success!" % fn)
            else:
                out.write(preline)
                preline = line
        return (False, "Unexpect Ends of data.")
    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b'Hello, world!')
    def do_POST(self):
        response = BytesIO()
        if "multipart" in self.headers['Content-Type'].lower():
            r, info = self.deal_post_data()
            print((r, info, "by: ", self.client_address))
            content="upload success"
        else:
            content_length = int(self.headers['Content-Length'])
            body = self.rfile.read(content_length)
           
            
            request=""
            content=""
            if isPy2:
                request=parseUrl(str(body))
            if isPy3:
                request=parseUrl(str(body,"utf8"))
            if 'cmd' in request:
                if (config['enable_cmd_auth']==1):
                    if (('ztk' not in self.headers) or ('zts' not in self.headers)):
                        self.send_response(403)
                        self.end_headers()
                        content=""
                        response.write(bytes(content))            
                        self.wfile.write(response.getvalue())
                        return
                else:   
                    content=execCmd(request['cmd'])
            # import urllib.parse
            # for k, v in urllib.parse.parse_qs(str(body,"utf8")):
            #     print(k,v)
        self.send_response(200)
        self.end_headers()            
        if isPy3:
            response.write(bytes(content,"utf8"))
        if isPy2:
            response.write(bytes(content))            
        self.wfile.write(response.getvalue())

# httpd = HTTPServer(('localhost', 8000), pyhttp)
# httpd.serve_forever()


def execCmd(args):
    with os.popen(args, "r", -1) as f:
        return (f.read())
def start_py3_http(isHttps=True,port=4043,host=""):
    httpd = HTTPServer((host, port), pyhttp)
    if isHttps:
        httpd.socket = ssl.wrap_socket (httpd.socket,
                keyfile=keyFile,
                certfile=certFile, server_side=True)
    httpd.serve_forever()        

def start_py2_http(isHttps=True,port=4080,host=""):
    httpd = HTTPServer((host, port), pyhttp)
    if isHttps:
        httpd.socket = ssl.wrap_socket (httpd.socket, 
                keyfile=keyFile, 
                certfile=certFile, server_side=True)
    httpd.serve_forever()
def start_http(*args):
    print(args)
    if isPy3:
        start_py3_http(args[0],args[1])
    elif isPy2:
        start_py2_http(args[0],args[1])

def start_http(*args):
    if isPy3:
        start_py3_http(*args)
    elif isPy2:
        start_py2_http(*args)   
try:
   _thread.start_new_thread(start_http, (True, config["httpsPort"],"") )
   _thread.start_new_thread(start_http, (False, config["httpPort"],"") )
except Exception as ex:
   print ("Error: 无法启动线程",ex)
while 1:
   pass